docs(agents): a local merge-tree of an os-regen path is not GitHub mergeability — state the corollary and name the sound probe (#15871) - #15885
Conversation
…regen path is not GitHub mergeability, and name the sound probe (#15871) AGENTS.md §11 already says the `merge=os-regen` driver is a LOCAL facility. What it never stated is the corollary that costs a seat a round trip: a local `git merge-tree` of a routed path runs the same merge-ort machinery as `git merge`, so it HONOURS the driver, while GitHub runs none — the two answer different questions about the same snapshot. The added bullet names the sound instrument (a throwaway bare clone sharing the object store, where the driver is genuinely absent, which is GitHub's actual condition) and refuses the falsified `-c merge.os-regen.driver=` spelling, whose empty string does not disable the driver but leaves git failing to run it and reporting a conflict for every routed path — including ones that text-merge cleanly. Measurements are on PR #15868, which carries the same text in `scripts/pm/os-regen-merge.sh`'s header. Part of #15815 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
维护者速读 · 待你一个字(skills 席代读,2026-09-05T13:3xZ;本 PR 属 devx 车道,其席位可更正)改了什么:AGENTS.md §11 加 10 行:本地 为什么改:今天 spec 席就是被这个假绿骗了一次(#15647 addendum 3 记的那件事);规则本体已经说驱动是本地设施,少的是这个推论。 风险与代价:CI 红——AGENTS.md 行数上限 1162,现在 1161,加 10 行就是 1171,行数 ratchet 拒绝;dev 没有擅自抬上限,如实标红等你裁。此外它与成员 5 的 PR #15856(同一文件,已重钉上限为 1058)撞车:谁先落地另一个都要重解。os-zhuang 已批准(批的是一张红 PR)。 选项
你要做的:回 A / B。 Generated by Claude Code |
A second, opposite symptom of the same root — measured today, offered as a second data point for this cardThis card states the corollary that a local Instance 1 — GitHub refuses a merge that is locally clean (PR #15838)
Instance 2 — git merges cleanly and produces a semantically stale file (PR #15966)Same file, different outcome.
The repo's own pre-commit os-regen check independently flagged the file as a generated artifact merged without a text merge and requiring regeneration. Repaired with the census's Why the pair is worth more than either⭐ Both come from the same root — a generated file whose content is line anchors, being text-merged — and they present as opposites: one refuses to merge while looking mergeable; the other merges while looking correct. A rule phrased only as "a clean One more property, from a third encounter today (PR #15838's resolution)When the census's ⛔ Filed as data, not as a proposed remedy — the sound-probe question is this card's and it is the maintainer's to settle. Generated by Claude Code |
Ceiling ruling —
|
Correction to the ceiling ruling, and the director seat now drives this PR to merge (2026-09-07)Maintainer reply, verbatim: 「15885 你接手跟进合并」. Correction. The batch #63 ruling above said "this PR lands first; #15856 rebases onto it". That sequencing was already false when written: #15856 (the rules-only rewrite) merged on 2026-09-05T13:48Z as Patch round (director seat, via a dev seat in a worktree; governed posture unchanged):
The maintainer's approval and armed auto-merge stand; if the push dismisses the approval, the maintainer will be asked to re-approve once, with the gate readings in hand. Generated by Claude Code |
…e the AGENTS.md ceiling 1058 -> 1068 (ruled) The rules-only rewrite of `AGENTS.md` landed while this branch was open, so the bullet this branch adds is re-typeset into that voice: the incident clause "and it has already cost a seat a round trip" comes out, and the rest is re-wrapped to the surrounding block's own prose width (widest added line 90 bytes, against 90 bytes widest in the §11 block around it; the gate's hard cap is 120). Every rule sentence stays, because each is ruled substance: a local `merge-tree` of a `merge=os-regen` path runs the same merge-ort machinery as `git merge` and therefore honours the custom driver while GitHub runs none, so the two answer different questions about the same snapshot; the sound probe is a throwaway bare clone that shares the object store with no driver registered, with both of its commands; and the `-c merge.os-regen.driver=` override is refused, with the reason it is refused — it does not disable the driver, it leaves git failing to run it and reporting a conflict for every routed path, including ones that text-merge cleanly. The bullet measures +10 lines against `origin/main`, taking `AGENTS.md` to 1068, so the `CEILINGS` entry moves 1058 -> 1068 at the landed count, headroom 0. That raise is the header's own escape hatch and it is ruled: maintainer, decision batch #63, 2026-09-07, verbatim and untranslated 「同意」 (PR #15885 comment 5564103435), and 「15885 你接手跟进合并」 (2026-09-07, quoted in the correction comment on the same PR, which re-measures the number the batch stated as 1171 against a `main` that had since moved). Re-wrap funding and a cross-file move were both refused per that header: the bullet is already at the block's prose width, and `AGENTS.md` is not a `CROSS_FILE_MOVES` destination, so no `ruledRaises` record applies. The widest-table-row leg (pin 768) and every other ceiling are untouched. Claude-Session: https://claude.ai/code/session_01TezFG8ZMrNH6n5VTNpPpdH Co-authored-by: Claude <noreply@anthropic.com>
|
os-dev-report Patch round complete — merged
|
| EXIT | command | verdict line |
|---|---|---|
| 0 | pnpm check:pm-skill-ratchet |
✓ AGENTS.md is 1068 lines (ceiling 1068; headroom 0). + ✓ AGENTS.md: widest table row is 768 bytes (pin 768; headroom 0). + ✓ declared cross-file moves: 1, total ceilings down 9 lines. |
| 0 | node scripts/pm/check-skill-line-ratchet.mjs --self-test |
✓ check-skill-line-ratchet self-test: 157 cases pass. |
| 0 | pnpm check:pm-skill-id-lint |
✓ check-skill-id-lint: 26 file(s) clean (pattern /#[0-9]{3,}/g). |
| 0 | pnpm check:pm-governed-prose |
✓ 2 instruction surface(s) name all 5 registered governed surfaces … and claim no others. |
| 0 | pnpm check:nul-bytes |
check-nul-bytes: OK (scanned 8137 text file(s); skipped 7 binary; no raw ASCII control bytes). |
| 0 | pnpm check:agent-test-spelling |
✓ 0 violations — 470 file(s) · 7123 bare -- token(s) · 1558 launcher-rooted run(s) |
| 0 | pnpm check:pm-governed-merges |
✓ check-governed-merges --self-test: 274 assertions |
| 0 | pnpm check:pm-dispatch-gates |
✓ dispatch-gates self-test: 1534 cases pass. |
| 0 | pnpm check:ratchet-remedy-authority |
OK — 219 scripts swept; 14 mark the expanding remedy ⛔ MAINTAINER-ONLY |
| 0 | pnpm check:bash32-floor |
✓ 29 tracked shell file(s) name no bash 4+ construct |
| 0 | pnpm check:cli-command-ids |
✓ 439 command-id literal(s) across 128 file(s) all resolve |
| 0 | pnpm check:cross-package-test-inputs |
OK: 28 package(s) read outside themselves, all declared |
| 0 | pnpm check:docs-audit-scope |
✓ scope injection is live |
| 0 | pnpm check:driver-memory-census |
OK — every declaration is ledgered, every ledger entry is live |
| 0 | pnpm check:entry-guard |
✓ 226 scripts/ file(s) — every entry guard goes through invoked-as.mjs |
| 0 | pnpm check:parse-guard |
✓ 225 scripts/ file(s) — every TypeScript parse goes through ts-parse.mjs. |
| 0 | pnpm check:pnpm-filter-targets |
✓ 144/188 --filter occurrence(s) across 36 file(s) resolve |
| 0 | pnpm check:refd-timer-probe |
✓ self-test: 11 cases pass, negative controls included. |
| 0 | pnpm check:required-contexts |
✓ 6 required context name(s) pinned across 2 workflow(s) |
| 0 | pnpm check:watch-hint-literal |
✓ 66 declaration(s) across 4 rostered name(s) |
| 0 | node packages/lint/scripts/check-reference-carrier-shape.mjs (+ --self-test) |
OK — 6276 file(s) scanned, 613 reference site(s). |
| 0 | node scripts/check-ci-filter-parity.mjs |
OK: all 169 declared cross-package glob(s) are covered |
| 0 | node scripts/check-closing-keyword-parity.mjs (+ --self-test) |
OK (3 parsers agree on all 9 keywords) · 24 assertions, 5 mutations driven to red |
| 0 | node scripts/check-comment-mask-corpus.mjs |
✓ 6276 files, 0 disagree, 0 unparseable, 77.9s |
| 0 | node scripts/check-declaration-mirrors.mjs (+ --self-test) |
All 29 self-test cases passed. |
| 0 | node scripts/check-scripts-symbol-anchors.mjs (+ --self-test) |
✅ 2935 anchors across 226 scripts resolve |
| 0 | node scripts/check-self-test-wired.mjs (+ --self-test) |
✓ every one of the 183 script(s) CI runs that ship a --self-test has it run by CI. |
| 0 | node scripts/check-self-test-workflow-commands.mjs (+ --self-test) |
✓ no self-test CI runs prints a line the runner would parse as a workflow command. |
| 0 | node scripts/check-whole-set-label-write.mjs (+ --self-test) |
✓ 0 violations — 282 file(s) over 3 root(s) |
| 0 | node scripts/pm/bare-root-worklist.mjs --self-test |
OK self-test: 78 live row(s) — none stale, none missing, none contradicted |
Governed-surface predicate — node scripts/pm/check-governed-merges.mjs --test AGENTS.md scripts/pm/check-skill-line-ratchet.mjs, EXIT=3:
governed-surface predicate: 1 of 2 path(s) hit the register (5 surfaces, repo-agnostic).
⛔ GOVERNED — a human merge is the review record for this PR (#9495 regime).
AGENTS.md ×1 — the repo-root agent instruction file
paths not on the register: scripts/pm/check-skill-line-ratchet.mjs
⇒ exit 3 is the expected GOVERNED posture, not a failure.
Ablation — the raised ceiling is load-bearing
Run from a tree where HEAD already carried the implementation, so the restore leg points at it. Mutation proven to reach disk before the reading was taken; restore proven by blob hash, never by an exit code:
HEAD blob: 90e7aa02570849d49397652849ddd8334169e1fd
pre-ablation: 90e7aa02570849d49397652849ddd8334169e1fd
anchor counts: 1068 before=1 after=0 ; 1058 after=1
mutated blob: d6d3926eab23c122464deddc1ad0d7245075cf72 (differs from HEAD blob: the edit landed)
ABLATION_EXIT=1
✗ check-skill-line-ratchet: AGENTS.md is 1068 lines; the ratchet ceiling is 1058. ...
Raising a ceiling requires a maintainer ruling quoted in the PR.
restored blob: 90e7aa02570849d49397652849ddd8334169e1fd (identical to HEAD blob)
git diff HEAD empty and git status clean after restore. Predicted direction RED, observed direction RED, with exactly the 1058-vs-1068 message. Re-run on the restored tree at the final commit: EXIT=0. The script carried trap ... EXIT INT TERM on absolute paths throughout.
Did the maintainer's approval survive the push?
Yes. Reviews read after the push: two APPROVED by os-zhuang, both still APPROVED (neither dismissed), both pinned to the pre-push commit ca2088e3d. Measured — not asserted — through the repo's own predicate, authorizedApprovalVerdict(reviews, 'f0e9c4c87...') from scripts/pm/check-governed-queue-guard.mjs:
GOVERNED_APPROVERS: os-zhuang, hotlong
state: "approved"
approvers: ["os-zhuang"]
approvalsOnEarlierCommits: [{ login: "os-zhuang", commitId: "ca2088e3d..." }]
unauthorizedApprovers: [], changesRequestedBy: []
Per the 2026-09-04 ruling that predicate encodes — 「只需要有人工批准记录就行,不需要卡最新的提交。」 — commit_id is not consulted to reach the verdict, and approvalsOnEarlierCommits is a printed reading that never branches one. So no re-approval is needed on account of this push. Auto-merge was left exactly as armed; no seat flipped ready, enqueued, or approved.
Two housekeeping readings for the director, not acted on
- The PR body's trailing attribution footer did not survive the
update_pull_requestPATCH. The body I sent ended with a rule line plus the bare_Generated by [Claude Code](https://claude.ai/code)_block; the stored body ends at the🤖 Generated with [Claude Code]line. I checked the rendered page, not only the API read, per the AGENTS.md rule that a body reading short through the API alone is probably intact — it is absent there too. I did not re-PATCH to re-add it: durable attribution is already in the body prose and the standing rule forbids looping on the footer. Flagging rather than fixing. - The
needs-user-decisionlabel is now stale — the ruling it was waiting on has landed and is quoted in the body. Removing it is the director's/PM's call, not mine, so it is untouched.
Structured report
{
"issue": 15871,
"status": "done",
"branch": "claude/issue-15871-agents-merge-tree-corollary",
"pr": "https://github.com/objectstack-ai/objectstack/pull/15885",
"premise_still_valid": true,
"summary": "Patch round on the existing PR #15885, no new branch and no new PR. Merged origin/main (78e8485d6) into the branch as merge commit f171510dc: clean, tree ad22eca70, AGENTS.md 1068 lines, the corollary bullet intact at the LOCAL-facility anchor (SS11 lines 586-595). Re-typeset the bullet in the rules-only voice of PR #15856: the incident clause 'and it has already cost a seat a round trip' removed, every rule sentence kept, re-wrapped to the surrounding block's measured 90-byte prose width (gate cap 120), every code span balanced within its line, 10 lines in and 10 lines out. Raised CEILINGS['AGENTS.md'] 1058 to 1068 with an entry comment quoting both rulings verbatim and untranslated; no ruledRaises record, since CROSS_FILE_MOVES was read and holds only platform-readings.md. Exactly two files changed. Pushed as a fast-forward to f0e9c4c87. PR body updated (body only). Two things flagged not fixed: the body's trailing attribution footer was dropped by GitHub on PATCH (verified absent on the rendered page, not re-posted per the no-footer-loop rule), and the needs-user-decision label is now stale.",
"tests": "36 gate families derived at the merge head via dispatch-gates.mjs --changed --commands --repo objectstack-ai/objectstack; all 36 run, all EXIT=0, exit codes captured before any pipe; nothing NOT MEASURED. Load-bearing: pnpm check:pm-skill-ratchet EXIT=0 -- 'AGENTS.md is 1068 lines (ceiling 1068; headroom 0)' and 'widest table row is 768 bytes (pin 768; headroom 0)' and 'declared cross-file moves: 1, total ceilings down 9 lines'; check-skill-line-ratchet.mjs --self-test EXIT=0, 157 cases pass; check-governed-merges.mjs --test EXIT=3 GOVERNED (expected posture). ABLATION: ceiling reverted to 1058 from a committed HEAD carrying the implementation; mutation proven on disk before the reading (anchor counts 1068 1-to-0, 1058 0-to-1; blob 90e7aa025 to d6d3926ea); gate went RED EXIT=1 with the 1058-vs-1068 message; restore proven by blob hash back to 90e7aa025 with git diff HEAD empty; trap EXIT INT TERM on absolute paths; re-run green at the final commit.",
"mcp_calls": "6",
"open_questions": [],
"out_of_scope_findings": []
}Generated by Claude Code
Patch round landed — head
|
Fixes #15871
Part of #15815 — the GOVERNED half. The ordinary half (the same text in
scripts/pm/os-regen-merge.sh's header, plus the driver's probe gate) is PR #15868.AGENTS.md§11 already says themerge=os-regendriver is a LOCAL facility. The corollary was nowhere stated: a localmerge-treeof a routed path is not evidence about GitHub's mergeability. This adds it as one bullet, immediately after that sentence. Nothing else inAGENTS.md; noCLAUDE.mdmirror (no gate demanded one).Ceiling raise — ruled
The ratchet ceiling for
AGENTS.mdinscripts/pm/check-skill-line-ratchet.mjsmoves 1058 → 1068, headroom 0, by the header's own escape hatch: a maintainer ruling quoted in this PR.Ruling 1 — decision batch #63, 2026-09-07, comment 5564103435. Maintainer reply, verbatim and untranslated:
which adopted "the line ratchet on
AGENTS.mdrises … for this PR's ten-line corollary (localmerge-treeis not GitHub mergeability; probe from a driver-less bare clone; ⛔ never-c merge.os-regen.driver=). Re-wrap and cross-file moves were correctly refused; this is the header's escape hatch."Ruling 2 — the correction, 2026-09-07, comment 5567414563. Maintainer reply, verbatim and untranslated:
Batch #63 stated the number as 1162 → 1171 and sequenced this PR before #15856. That sequencing was already false when written: #15856 (the rules-only rewrite) merged on 2026-09-05 as
abdceef8c, andAGENTS.mdonmainis now 1058 with the ceiling re-pinned to 1058. The ruling's substance stands — the ten-line corollary is approved and its raise is the escape hatch — and the number is re-measured here, mechanically, at the landed count.AGENTS.mdis not aCROSS_FILE_MOVESdestination (verified:CROSS_FILE_MOVESholds exactly one key,.claude/skills/pm-dispatch/references/platform-readings.md), so noruledRaisesrecord applies — batch #63's mention of one is withdrawn by the correction.MAX_TABLE_ROW_BYTESand every other ceiling are untouched.Ledger, re-measured on this head
AGENTS.mdonorigin/main(78e8485d6)git diff origin/main -- AGENTS.md1 file changed, 10 insertions(+)— the bullet and nothing elseAGENTS.mdWhat this patch round did
origin/maininto the branch (a merge commit; no rebase, no amend, no force-push). Clean: merge treead22eca70e3b08f1ec764511161754a26686549c,AGENTS.md= 1068 lines, the bullet landing at §11 lines 586–595 directly under the "The driver is a LOCAL facility" sentence it anchors to.-c merge.os-regen.driver=refusal with its reason. Re-wrapped to the surrounding block's own prose width — widest added line 90 bytes, against 90 bytes widest in the surrounding §11 block (the gate's hard cap is 120). Every inline code span is balanced within its line.Exactly two files change:
AGENTS.md(the one bullet) andscripts/pm/check-skill-line-ratchet.mjs(oneCEILINGSentry + its comment).The added text, exactly as committed
The placeholders are spelled
BASE HEADin words rather than in angle brackets, keeping the paragraph quotable in a GitHub body without tripping the body sanitizer.Verification
Gate families derived with
node scripts/pm/dispatch-gates.mjs --changed --commands --repo objectstack-ai/objectstackat the merge head — 36 commands (19 pnpm, 17 direct node) over the 2-path change set. Every one was run; exit codes captured BEFORE any pipe (cmd > log 2>&1; EXIT=$?).All 36 GREEN, EXIT=0, no exceptions. Nothing in this round is NOT MEASURED.
pnpm check:—agent-test-spelling·bash32-floor·cli-command-ids·cross-package-test-inputs·docs-audit-scope·driver-memory-census·entry-guard·nul-bytes·parse-guard·pm-dispatch-gates·pm-governed-merges·pm-governed-prose·pm-skill-id-lint·pm-skill-ratchet·pnpm-filter-targets·ratchet-remedy-authority·refd-timer-probe·required-contexts·watch-hint-literalnode—packages/lint/scripts/check-reference-carrier-shape.mjs(+--self-test) ·scripts/check-ci-filter-parity.mjs·check-closing-keyword-parity.mjs(+--self-test) ·check-comment-mask-corpus.mjs·check-declaration-mirrors.mjs(+--self-test) ·check-scripts-symbol-anchors.mjs(+--self-test) ·check-self-test-wired.mjs(+--self-test) ·check-self-test-workflow-commands.mjs(+--self-test) ·check-whole-set-label-write.mjs(+--self-test) ·scripts/pm/bare-root-worklist.mjs --self-testPlus, outside the derived set:
node scripts/pm/check-skill-line-ratchet.mjs --self-testEXIT=0 —✓ check-skill-line-ratchet self-test: 157 cases pass.(it assertsCEILINGS.has('AGENTS.md'), not the number, and still passes).Selected verdict lines, quoted:
The ratchet's own verdict lines, quoted:
The table-row leg is untouched by this PR —
MAX_TABLE_ROW_BYTESwas not edited, and the bullet is prose, not a table row. The cross-file-move leg is likewise unchanged:✓ … declared cross-file moves: 1, total ceilings down 9 lines.Governed-surface predicate —
node scripts/pm/check-governed-merges.mjs --test AGENTS.md scripts/pm/check-skill-line-ratchet.mjs, EXIT=3, quoted:⇒ exit 3 is the expected posture, not a failure. No seat flips this ready, enqueues it, or arms auto-merge; the maintainer's approval and armed auto-merge stand untouched by this round.
Ablation — the raised ceiling is load-bearing
The ceiling was temporarily put back to 1058 and the gate re-run, from a tree where
HEADalready carries the implementation (so the restore leg points at it). The mutation was proven to reach disk before the reading was taken, and the restore proven by blob hash — not by an exit code:git diff HEADis empty after the restore, andgit statusis clean. Predicted direction was RED, observed direction was RED, with the 1058-vs-1068 message — so the raised ceiling is load-bearing and the gate is not vacuous. The script carried atrap … EXIT INT TERMrestore on absolute paths throughout. Re-run on the restored tree at the final commit: EXIT=0, both legs green as quoted above.Docs + a PM script; publishes nothing from any package ⇒
skip-changeset(already labelled).#15856 (the rules-only rewrite,
AGENTS.md−103 net, re-pin 1162 → 1058) merged asabdceef8con 2026-09-05. This branch now carries that merge, and the bullet is re-typeset into the rewritten §11 in that PR's voice — which is what the correction ruling ordered. #15427 is not addressed here.🤖 Generated with Claude Code